# -*- coding: utf-8 -*-
from __future__ import unicode_literals
'''
模块名不可以为'code', 因为 werkzeug 中使用了
http://stackoverflow.com/questions/7880827/werkzeug-attributeerror-module-object-has-no-attribute-interactiveinterprete
'''
import os
import sys
import re

from datetime import datetime, timedelta

try:
    from urllib.parse import quote, urlparse, parse_qs
except ImportError:
    from urllib import quote
    from urlparse import urlparse, parse_qs

try:
    import json
except ImportError:
    import simplejson as json

from flask import Flask, render_template, url_for, send_from_directory, redirect, request, make_response, g, session, flash, abort

from werkzeug.contrib.fixers import ProxyFix

from . import extra_config

def create_app():

    app = Flask(
        __name__,
        static_folder='static',
        template_folder='templates',
        instance_relative_config=True
    )
    app.config.from_object('config.default')
    app.config.from_pyfile('config.py') # 从instance文件夹中加载配置

    app.wsgi_app = ProxyFix(app.wsgi_app)

    from .ensure import Ensure
    Ensure(app, extra_config).ensureAll()

    from .smtpwrapper import SMTPWrapper
    mailer = SMTPWrapper(**extra_config.SMTP_CONFIG)

    from .util import RegexConverter
    app.url_map.converters['regex'] = RegexConverter

    from .logwrapper import LogWrapper
    app.loger = LogWrapper(extra_config.LOG_FOLDER)

    from werkzeug.contrib.cache import SimpleCache
    app.cache = SimpleCache()

    app = config_template_filter(app)
    app = config_template_global(app)
    app = config_request_hook(app)
    app = config_context_processor(app)
    app = config_errorhandler(app)
    app = config_blueprint(app)
    app = config_direct_route(app)

    app = config_debug(app)
    return app


def config_template_filter(_app):

    @_app.template_filter('_CFG')
    def get_config(cfg_key):
        from .util import read_config
        return read_config(extra_config, cfg_key)

    @_app.template_filter('_AVOID_NONE')
    def avoid_none(_val):
        if _val is None:
            return ''
        else:
            return _val

    @_app.template_filter('_NOT_SET')
    def not_set(_val):
        if _val is None:
            return '<未设置>'
        else:
            return _val

    @_app.template_filter('_IS_NONE')
    def is_none(_val):
        return _val is None

    @_app.template_filter('_LOGIND')
    def is_logind(user):
        return hasattr(user, '_id')

    @_app.template_filter('_JS_OBJ')
    def is_logind(val):
        return val if bool(val) else '{}'
    
    return _app

def config_template_global(_app):

    @_app.template_global('url_for')
    def static_url(endpoint, **values):
        '''重写模板中的url_for函数，用于控制浏览器缓存'''
        _url = url_for(endpoint, **values)
        if endpoint == 'static':
            client_version = request.cookies.get('client_version')
            _client_version = 1
            if bool(client_version) and client_version.isdigit():
                _client_version = int(client_version)
            _server_version = _app.config.get('server_version', 1)
            if _server_version > _client_version:
                from .util import getTimeStamp
                _url += '?{0}'.format(getTimeStamp())
        return _url
    
    return _app

def config_request_hook(_app):

    @_app.before_request
    def before_request():
        '''请求开始之前，可以获取请求对象(request)'''
        # print('before_request')
        if not _app.cache.has('users_public_list'):
            _app.cache.set('users_public_list', {})

    @_app.after_request
    def after_request(response):
        '''请求完成之后，对应的响应发送到客户端之前，可以修改响应对象(response)'''
        if response.status_code == 302:
            if 'Location' in response.headers:
                location_url = response.headers['Location']
                login_url = url_for(_app.config['login_route'])
                if location_url == login_url:
                    # 此处设置 `response.headers['Location']` 并不能达到效果，后面 `url_for` 时获取不到
                    _char = '&' if '?' in location_url else '?'
                    _redirect_url = re.sub(
                        r'https?\:\/{2}([0-2]?\d{1,2}\.){3}[0-2]?\d{1,2}(:\d{1,5})?',
                        extra_config.PLATFORM['VISIT_BASE'],
                        request.url
                    )
                    if not _redirect_url.endswith('/user/confirm/') and not _redirect_url.endswith('/user/logout/'):
                        response.headers['Location'] = '{0}{1}next={2}'.format(
                            location_url,
                            _char,
                            quote(_redirect_url)
                        )
        return response

    @_app.teardown_request
    def teardown_request(exception):
        '''本次请求的响应完成，可以清理资源，销毁本次请求'''
        # print('teardown_request')
        pass

    return _app

def config_context_processor(_app):

    @_app.context_processor
    def get_logined_user():
        logined_user = 'None'
        return {
            'logined_user': logined_user
        }

    return _app

def config_errorhandler(_app):

    @_app.errorhandler(403)
    def page_forbidden(error=None):
        return render_template('_error/403.html'), 403

    @_app.errorhandler(404)
    def page_not_found(error=None):
        return render_template('_error/404.html'), 404

    @_app.errorhandler(500)
    def page_server_error(error):
        return render_template("_error/500.html"), 500

    return _app

def config_blueprint(_app):

    from .Admin.main import admin
    _app.register_blueprint(admin, url_prefix='/admin')

    from .File.main import _file
    _app.register_blueprint(_file, url_prefix='/file')

    return _app

def config_direct_route(_app):

    @_app.route(r'/<regex("favicon\.(ico|png)"):icon>')
    def favicon(icon):
        return send_from_directory(os.path.join(_app.static_folder, 'img'), icon)

    @_app.route(r'/', methods=['GET', 'POST'])
    def home():
        '''首页'''
        _tmp = _app.static_folder
        _tmp = os.path.dirname(_tmp)
        _tmp = os.path.dirname(_tmp)
        _path = os.path.join(_tmp, 'test.rmk')
        _c = ''
        if os.path.exists(_path) and os.path.isfile(_path):
            if request.method == 'POST':
                _c = request.values.get('content', None)
                _result = ''
                if bool(_c):
                    # _c = _c.encode('utf-8', 'ignore')
                    print('begin')
                    from .richmarkup import Parser, get_default_theme, get_default_action
                    print('import over')
                    _ps = Parser(_c)
                    _html = '\n'.join([
                        '<!DOCTYPE html>',
                        '<html>',
                        '<head>',
                            '<meta charset="utf-8" />',
                            '<title>demo</title>',
                            '<style type="text/css">',
                                '{css}',
                            '</style>',
                        '</head>',
                        '<body>',
                            '{html}',
                            '<script type="text/javascript">',
                                '{js}',
                            '</script>',
                        '</body>',
                        '</html>'
                    ])
                    print('init over')
                    ret = _ps.parse()
                    theme = get_default_theme()
                    action = get_default_action()
                    _result = _html.format(
                        css=theme,
                        html=ret,
                        js=action
                    )
                    print('end')
                return _result
            with open(_path, 'r') as _f:
                _c = _f.read()
        return render_template('home/pages/index.html', content=_c)

    @_app.route(r'/login/', methods=['GET', 'POST'])
    def login():
        '''登录'''
        from .util import in_text_range, text_required
        if request.method == 'POST':
            _user = request.values.get('email-user', None)
            if text_required(_user):
                pass
            flash('用户名或密码错误')
        return render_template('login.html')

    return _app

def config_debug(_app):

    '''for debug * begin'''
    @_app.route(r'/403/')
    def fot():
        return abort(403)

    @_app.route(r'/404/')
    def fof():
        return abort(404)

    @_app.route(r'/500/')
    def foo():
        return abort(500)
    '''for debug * end'''

    return _app